/*
 * serveClient.java
 *
 * Created on January 7, 2006, 5:16 PM
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 * Open. You can then make changes to the template in the Source Editor.
 */

/**
 *
 * @author Sujal Bista
 */

import java.net.*;
import java.io.*;
import java.util.StringTokenizer;

public class serveClient extends Thread
{
    private Socket socket;

    //index to the judge in the global data array
    private int judgeIndex;

    //output structure
    private showOutput output;
    
    private BufferedReader socketInput;
    
    private PrintWriter socketOutput;
    
    //judge specific Used by judge A
    public int location;
    public int individiualDifficultyJudged;

    /** Creates a new instance of serveClient */
    public serveClient(Socket socket,showOutput output)
    {
        this.socket=socket;
        this.output=output;
        individiualDifficultyJudged=0;
    }
    
    public void sendMessage(String message)
    {
        System.err.println("Sending message: " + message);
        socketOutput.println(message);
        output.printLn(message);        
    }

    public void run()
    {
        

        String inSocket,outSocket;
        
        // print received data
        try
        {
            socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            socketOutput = new PrintWriter(socket.getOutputStream(),true);
            while(true)
            {
                              
                inSocket = socketInput.readLine();

                if (inSocket==null) break;

                //temporary closing condition
                if(inSocket.indexOf("fff")>-1)
                    socketOutput.println("ATFN");


                outSocket=processPacket(inSocket);
                if(outSocket.length()!=0)
                {
                    socketOutput.println(outSocket);
                    output.printLn(outSocket);
                }
            }
            ///should close it
            globalData.judges[judgeIndex].endAthlete();
        }
        catch (IOException e)
        {
            globalData.freeJudge(judgeIndex); //globalData.judgesConnected[judgeIndex]=false;
            output.error(e.toString());
        }

        // connection closed by client
        try
        {
            socket.close();
            output.printLn("Connection closed by client");
        }
        catch (IOException e)
        {
            output.error(e.toString());
        }
    }

    private String processPacket(String packet)
    {
        //type of judge
        judge.judgeType jType;

        System.err.println("packet: " + packet);
        
        String outputLine;

        //determine the command
        if(packet.startsWith("INIT "))//judge init
        {
            //removes the commmand
            packet=packet.substring(5);

            String jTypeS=packet.substring(0,packet.indexOf(' '));
            String jSign=packet.substring(packet.indexOf(' ')+1);

            output.printLn(jTypeS);
            output.printLn(jSign);

            if(jTypeS.compareToIgnoreCase("judgeA")==0)
                jType=judge.judgeType.judgeA;
            else if(jTypeS.compareToIgnoreCase("judgeB")==0)
                jType=judge.judgeType.judgeB;
            else
                jType=judge.judgeType.judgeC;

            //get the global index from the judge list that has not been used
            int i=globalData.getFreeJudge(jType);
            if(i==-1)
            {
                outputLine="";
                return outputLine;
            }
            judgeIndex=i;
            globalData.clients[judgeIndex]=this;
            //set the user added flag
            globalData.setUserAdded(true);
            
            //deter
            System.out.println(packet);
            
            globalData.judges[judgeIndex]=new judge(jType,jSign);
            
            if(globalData.athleteActive==true)
            {
                outputLine="SCOR "+ globalData.scoringSystem;
                socketOutput.println(outputLine);
                
                globalData.judges[judgeIndex].endAthlete();
                globalData.currentAthlete.clearJudgesData(judgeIndex);
                globalData.judges[judgeIndex].beginAthlete(globalData.currentAthlete.getName());
                
                globalData.currentAthlete.setJudgeConnected(judgeIndex,globalData.judgesConnected[judgeIndex]);
                globalData.currentAthlete.setJudgeType(judgeIndex,globalData.judges[judgeIndex].type);
                
                //load an athlete and send its info to the corresponding judge
                outputLine="ATHL "+ globalData.scoringSystem +" " +globalData.currentAthlete.toString();
                socketOutput.println(outputLine);
                
                outputLine="EVNT "+ globalData.currentGroup + " "+ globalData.currentGender + " "+ globalData.currentEvent.getevent();
                socketOutput.println(outputLine);
                globalData.clients[i].individiualDifficultyJudged=0;
                globalData.clients[i].location=0;
                
                outputLine="";
            }
            else
                outputLine="";
            individiualDifficultyJudged=0;
            location=0;
        }
        else if(packet.startsWith("JTYPE"))//reset judge type
        {
            packet=packet.substring(6);
            
            String jTypeS=packet;
            
            if(jTypeS.compareToIgnoreCase("judgeA")==0)
                jType=judge.judgeType.judgeA;
            else if(jTypeS.compareToIgnoreCase("judgeB")==0)
                jType=judge.judgeType.judgeB;
            else
                jType=judge.judgeType.judgeC;
            
            globalData.judges[judgeIndex].setType(jType);
            if(globalData.athleteActive==true)
                globalData.currentAthlete.setJudgeType(judgeIndex,globalData.judges[judgeIndex].type);
            
            outputLine="";
        }        
        else if(packet.startsWith("DATA"))//judge init
        {
            //removes the commmand
            packet=packet.substring(5);
            globalData.judges[judgeIndex].updateAthelete(packet);
            
            if(globalData.judges[judgeIndex].type==judge.judgeType.judgeC)
                processPacketForJudgeC(packet);
            else if(globalData.judges[judgeIndex].type==judge.judgeType.judgeB)
                processPacketForJudgeB(packet);
            else if(globalData.judges[judgeIndex].type==judge.judgeType.judgeA)
                processPacketForJudgeA(packet);
            
            outputLine="";
        }
        else
            outputLine=packet;
        return outputLine;
    }
    
    
    //processes packet related to judge A
    private void processPacketForJudgeA(String packet)
    {
        //if(globalData.athleteScorable == false) 
        //    return;

        //check if the mistake message has been received
        if(packet.indexOf("Mistake")!=-1) 
        {
            location=(int)(globalData.getTime()/10);
            boolean found=false;
            int i,j;

            //add the data in the list based on the time in that judge's database
            if(!found)
                globalData.currentAthlete.addJudgeData(judgeIndex,new point(location,-1));//mistake seen by not seen by two judges
            else
                globalData.currentAthlete.addJudgeData(judgeIndex,new point(location,-1));    //mistake seen by atleast two judges
        }
        else if (packet.startsWith("Cancel"))   //check if the cancel message has been received
        {
            //remove data
            if(globalData.currentAthlete.getJudgeVector(judgeIndex).size()>0)
            {
                point p=globalData.currentAthlete.removeJudgeData(judgeIndex, globalData.currentAthlete.getJudgeVector(judgeIndex).size()-1);
                int i,j,k,l;
                //if the other judge has mistake within 3 sec then do special calculation
                for(i=0;i<(globalData.totalJudges-1) && p.y==1;i++) 
                {
                    if(globalData.judges[i].type!=judge.judgeType.judgeA)
                        continue;
                    for(j=0;j<globalData.currentAthlete.getJudgeVector(i).size();j++)
                    {
                        //check if anything is between 3 sec has been set
                        if( java.lang.Math.abs((int)p.x-(int)(globalData.currentAthlete.getJudgeData(i,j)).x)<300 && (int)(globalData.currentAthlete.getJudgeData(i,j)).y ==1 )
                        {
                            boolean found=false;
                            for(k=0;k<(globalData.totalJudges-1) && !found ;k++) 
                            {
                                if(globalData.judges[k].type!=judge.judgeType.judgeA || i==k)
                                    continue;
                                for(l=0;l<globalData.currentAthlete.getJudgeVector(k).size();l++)
                                {
                                    //check if anything is between 3 sec
                                    if( java.lang.Math.abs((int)(globalData.currentAthlete.getJudgeData(k,l)).x-(int)(globalData.currentAthlete.getJudgeData(i,j)).x)<300)
                                    {
                                        found=true;
                                        break;
                                    }
                                }
                            }

                            //if nothing is within range remove the element
                            if(!found)
                                globalData.currentAthlete.setJudgeData(i,j,new point(globalData.currentAthlete.getJudgeData(i, j).x,0));
                        }
                    }
                }


            }
        }
        else if (packet.startsWith("Codes"))
        {
            // Parse the codes that belong to each deduction
            System.err.println("Got codes: " + packet);
            StringTokenizer tokens = new StringTokenizer(packet);
            tokens.nextToken();
            int l = 0;
            while (tokens.hasMoreTokens()) {
                int code=0;
                try
                {
                    code = Integer.parseInt(tokens.nextToken());
                }
                catch (NumberFormatException e)
                {
                }
                //System.err.println("Token: " + code);
                globalData.currentAthlete.setJudgeData(judgeIndex,l,new point(globalData.currentAthlete.getJudgeData(judgeIndex,l).x,code));
                l++;
            }
        }
    }

    //processes packet related to judge B
    private void processPacketForJudgeB(String packet)
    {
        //if(globalData.athleteScorable == false) 
        //    return;
        float f=Float.valueOf(packet.trim());
        System.err.println("Received B Judge packet: " + packet);
        globalData.currentAthlete.addJudgeData(judgeIndex,new point(f,0));
    }
    
    //processes packet related to judge C
    private void processPacketForJudgeC(String packet)
    {
        //if(globalData.athleteScorable == false) 
        //    return;
        
        if(packet.indexOf("Undo")==-1)   //compute location if undo is not pressed
        {
            int nanduCount=globalData.currentAthlete.getNanduCount();
            int temp=0;
            boolean notConnected=true;

            //find appropriate distance
            for(int i=0;i<nanduCount;i++)
            {
                String nanduCode=globalData.currentAthlete.getNandu(i);
                nanduData.nandu nanduDesc=globalData.nanduList.find(nanduCode);
                temp+=nanduDesc.getTotalMovements();
                if(individiualDifficultyJudged==temp)
                {
                    if(i+1<nanduCount)
                        notConnected=false;
                    break;
                }
                else
                if(individiualDifficultyJudged<temp)
                    break;                    
            }

            //put right distance
            if(notConnected==true)
                location+=50;
            else
                location+=100;

        }
        //process and assign  specific locations
        if(packet.indexOf("Success")!=-1)   //atlete succeded
        {
            globalData.currentAthlete.addJudgeData(judgeIndex,new point(location,1));    //athlete hit it
            individiualDifficultyJudged++;
        }
        else if(packet.indexOf("Fail")!=-1) //athlete failed
        {
            globalData.currentAthlete.addJudgeData(judgeIndex,new point(location,0));    //athlete made a mistake
            individiualDifficultyJudged++;
        }
        else    //undo button pressed
        {
            if(globalData.currentAthlete.getJudgeVector(judgeIndex).size()>0)
                globalData.currentAthlete.removeJudgeData(judgeIndex,globalData.currentAthlete.getJudgeVector(judgeIndex).size()-1);
            individiualDifficultyJudged--;

            int nanduCount=globalData.currentAthlete.getNanduCount();
            int temp=0;
            boolean notConnected=true;

            //find appropriate distance
            for(int i=0;i<nanduCount;i++)
            {
                String nanduCode=globalData.currentAthlete.getNandu(i);
                nanduData.nandu nanduDesc=globalData.nanduList.find(nanduCode);
                temp+=nanduDesc.getTotalMovements();
                if(individiualDifficultyJudged==temp)
                {
                    if(i+1<nanduCount)
                        notConnected=false;
                    break;
                }
                else
                if(individiualDifficultyJudged<temp)
                    break;                    
            }

            //put right distance
            if(notConnected==true)
                location-=50;
            else
                location-=100;


        }
        
    }
}
